import React, { PureComponent } from 'react';
import { connect } from 'dva';
import { Card, message, Form, Input, Modal, Checkbox, Button, Upload, Select, Radio } from 'antd';
import { FormInstance } from 'antd/lib/form';
import { UploadOutlined, FolderOpenOutlined, SaveOutlined, DownloadOutlined } from '@ant-design/icons';
import JSZip from 'jszip';
import * as xmind from 'xmind';
import { Graph, Model, Node, Edge, Shape } from '@antv/x6'
import Hierarchy from '@antv/hierarchy';
import TreeView from '../treeView'

interface HierarchyResult {
  id: number
  x: number
  y: number
  data: {
    faultCode: string
    faultDescription: string
  }
  children: HierarchyResult[]
}
const mapStateToProps = (state: any) => ({
  knowledgeBreakdown: state.knowledgeBreakdown,
  // loading: state.loading.effects['knowledgeBreakdown/postObjWithRes'],
});

class BreakdownViewModal extends PureComponent<any, any> {
  // refElement = React.createRef();
  constructor(props: any) {
    super(props);
    this.state = {
      currentData: [],  //  tree数据
      screenFit: '1',
      currentIds: {}, //  tree数据节点关系
      currentTargetModel: [],
    };
  }

  componentDidMount() {
    const { dispatch } = this.props;
    this.props.onRef(this);
  }

  componentDidUpdate(prevProps: any) {
    const { modalVisible, record, dispatch} = this.props
    if (modalVisible && modalVisible !== prevProps.modalVisible) {
      dispatch({
        type: 'http/getDataWithRes',
        payload: { 
          url: '/mscontent/knowledge/fault/list',
          majorCode: record.majorCode,
          rootId: record.rootId,
          pageNo: 1,
          pageSize: 9999,
        },
        callback: (res: any) => {
          //  获取完整tree
          if (res.statusCode == '0') {
            if (res?.data?.list && res?.data?.list.length > 0) {
              //  通过 parentId 转成 tree
              const sourceData = this.arrayToTree(res?.data?.list, 'parentId');
              //  设置 parrentCode
              const sourceDataList = this.treeToArray(sourceData, '');
              const fullData = this.formatTreeData(sourceDataList);
              const fullDataIds = this.getFulltreeIds(fullData);
              //  计算坐标
              const fullDataModel = this.getCoordinates(fullData[0]);
              //  整理tree视图数据
              const fullTargetModel = this.transformModel(fullDataModel, fullDataIds);
              this.setState({
                currentData: fullData,
                currentIds: fullDataIds,
                currentTargetModel: fullTargetModel
              }, () => {
                this.treeViewRef.setData(fullTargetModel, fullDataIds);
              })
            }
          }
        }
      })
    }
  }

  formatTreeData = (list: any[]) => {
    const tempList = JSON.parse(JSON.stringify(list));
    let tempFullData: any[] = [];
    tempList && tempList.forEach((item: any) => {
      tempFullData[item.faultCode] = {
        ...item,
      };
    });
    return this.arrayToTree1(Object.values(tempFullData));
  }

  arrayToTree1 = (list: any[]) => {
    let res = []; // 存放结果集
    let map = {};
    // 判断对象是否有某个属性
    let getHasOwnProperty = (obj: any, property: any) => Object.prototype.hasOwnProperty.call(obj, property);
    // 边做map存储，边找对应关系
    for (const i of list) {
      map[i.faultCode] = {
        ...i,
        children: getHasOwnProperty(map, i.faultCode)
          ? map[i.faultCode].children
          : [],
      };
      const newItem = map[i.faultCode];
      if (i.parrentCode === "") {
        res.push(newItem);
      } else {
        if (!getHasOwnProperty(map, i.parrentCode)) {
          map[i.parrentCode] = {
            children: [],
          };
        }
        map[i.parrentCode].children.push(newItem);
      }
    }
    return res;
  }

  //  处理后台数据，通过 parentId 构建树
  arrayToTree = (list: any[], pKey: string) => {
    let res = []; // 存放结果集
    let map = {};
    // 判断对象是否有某个属性
    let getHasOwnProperty = (obj: any, property: any) => Object.prototype.hasOwnProperty.call(obj, property);
    // 边做map存储，边找对应关系
    for (const i of list) {
      map[i.id] = {
        ...i,
        title: i.faultCode + '-' + i.faultDescription,
        children: getHasOwnProperty(map, i.id)
          ? map[i.id].children
          : [],
      };
      const newItem = map[i.id];
      if (!i[pKey]) {
        // newItem[pKey] = i.faultCode;
        res.push(newItem);
      } else {
        if (!getHasOwnProperty(map, i[pKey])) {
          map[i[pKey]] = {
            children: [],
          };
        }
        map[i[pKey]].children.push(newItem);
      }
    }
    return res;
  }

  //  设置 parrentCode
  treeToArray = (tree: any, pcode: string) => {
    let res: any[] = [];
    for (const item of tree) {
      const {
        children,
        faultCode,
        // faultDescription,
        ...i
      } = item;
      if (children && children.length > 0) {
        const temp = this.treeToArray(children, faultCode);
        res = res.concat(temp);
      }
      res.push({
        faultCode,
        // faultDescription,
        parrentCode: pcode,
        ...i
      });
    }
    return res;
  }

  //  获取完整树节点关系
  getFulltreeIds = (data: any[]) => {
    const ids = {};
    function formatData(tree: any[]) {
      for (let item of tree) {
        const { children } = item
        ids[item.faultCode] = [];
        if (children.length > 0) {
          ids[item.faultCode] = children.map(t => t.faultCode);
          formatData(children)
        }
      }
    }
    if (data[0]) {
      const topicChildren = data[0]?.children || [];
      ids[data[0].faultCode] = topicChildren.map(t => t.faultCode);
      topicChildren && formatData(data[0]?.children);
    }
    return ids;
  }
  
  //  计算坐标
  getCoordinates = (data: any) => {
    const result = Hierarchy.mindmap(data, {
      direction: 'H',
      getHeight() {
        return 120
      },
      getWidth() {
        return 100
      },
      getHGap() {
        return 200
      },
      getVGap() {
        return 1
      },
      getSide: () => {
        return 'right'
      },
    })
    const model: Model.FromJSONData = { nodes: [], edges: [] };
    const traverse = (data: HierarchyResult) => {
      if (data) {
        model.nodes?.push({
          id: `${data.data.faultCode}`,
          x: data.x + 250,
          y: data.y + 250,
          code: data.data.faultCode,
          desp: data.data.faultDescription,
          // title: data.data.faultDescription,
          shape: 'circle',
          width: 260,
          height: 88,
          attrs: {
            body: {
              fill: '#5F95FF',
              stroke: 'transparent',
              rx: 10,
              ry: 10,
            },
          },
        })
      }
      if (data.children) {
        data.children.forEach((item: HierarchyResult) => {
          model.edges?.push({
            source: `${data.data.faultCode}`, //  data.id
            target: `${item.data.faultCode}`, //  data.id
            attrs: {
              line: {
                stroke: '#A2B1C3',
                strokeWidth: 1,
                targetMarker: null,
              },
            },
          })
          traverse(item)
        })
      }
    }
    traverse(result);
    return model;
  }

  //  转换数据
  transformModel = (model: any, ids: any) => {
    let data = JSON.parse(JSON.stringify(model));
    const { nodes, edges } = data
    let targetModel: any = { nodes: [], edges: edges };
    nodes.forEach((n: any, idx: number) => {
      let tempInfo = {
        code: '',
        text: n.desp
      };
      if (idx !== 0) {
        //  起始
        tempInfo.code = n.code;
      }
      let tempN = {
        id: n.id,
        shape: 'tree-node',
        width: 260,
        height: 88,
        leaf: !(ids[n.id] && ids[n.id].length > 0),
        leafLen: ids[n.id] ? ids[n.id].length : 0,
        x: n.x,
        y: n.y,
        attrs: {
          code: {
            textWrap: {
              text: tempInfo.code
            }
          },
          label: {
            textWrap: {
              text: tempInfo.text
            }
          }
        }
      }
      targetModel.nodes.push(tempN);
    })
    return targetModel;
  }

  //  取消操作
  cancel = () => {
    const { closeModal,  } = this.props;
    closeModal();
    this.setState({
      currentData: [],
      screenFit: '1',
      currentIds: {},
      currentTargetModel: [],
    })
    this.treeViewRef && this.treeViewRef.clearGraph();
  }

  //  下载知识库树
  downloadKownledgeTree = () => {
    const { currentData, currentIds } = this.state;
    const {Workbook, Topic, Dumper, Marker} = xmind;
    if (!(currentData && currentData.length > 0)) return;
    const topicTitle = currentData[0].faultDescription;
    const workbook = new Workbook();
    const topic = new Topic({sheet: workbook.createSheet('topic', topicTitle)});
    function loopCreate(tree: any[]) {
      for (let item of tree) {
        const { children, faultCode, faultDescription } = item;
        // const tempTitle = faultCode + '-' + faultDescription;
        if (children.length > 0) {
          let tempCid = '';
          if (!faultCode || faultCode === 'topic') {
            tempCid = faultDescription
          } else {
            tempCid = faultCode + '-' + faultDescription;
          }
          children.forEach((c: any) => {
            const { faultCode = '', faultDescription = '' } = c;
            topic
              .on(topic.cid(tempCid))
              .add({title: faultCode + '-' + faultDescription})
          })
          loopCreate(children);
        }
      }
    }
    loopCreate(currentData);
    const dumper = new Dumper({workbook});
    const files = dumper.dumping();
    const jszip = new JSZip();
    for (const file of files) {
      jszip.file(file.filename, file.value);
    }
    jszip.generateAsync({ type:'blob' }).then((content) => {
      const link = document.createElement('a');
      link.href = URL.createObjectURL(content);
      link.download = `${topicTitle}.xmind`;
      link.click();
      link.remove();
    });
  }

  //  画笔比列
  handleGraphFit = (val: any) => {
    this.setState({
      screenFit: val,
    })
    if (this.treeViewRef) {
      const { graph } = this.treeViewRef.state;
      if (val === '1' ) {
        //  适应画布
        graph && graph.zoomToFit({ padding: 24 });
      } else if (val === '2') {
        //  100%
        graph && graph.zoomTo(1);
      }
    }
  }

  render() {
    const { modalVisible } = this.props;
    const { screenFit } = this.state;
    const footer = (
      <div>
        <Button size="small" onClick={this.cancel}>
          关闭
        </Button>
      </div>
    );
    return (
      <Modal
        style={{ top: 20 }}
        footer={footer}
        title="故障树"
        width={1200}
        // height={600}
        bodyStyle={{ maxHeight: '800px' }}
        visible={modalVisible}
        onCancel={this.cancel}
      >
        <div style={{ width: '100%', marginBottom: '15px' }}>
          <Button onClick={() => this.downloadKownledgeTree()} icon={<DownloadOutlined />}>下载</Button>
        </div>
        <TreeView
          onRef={(modalRef: any) => (this.treeViewRef = modalRef)}
          clickNode={(n: any) => {
            // console.log(n);
          }}
          styels={{
            width: '100%',
            height: '700px'
          }}
        />
        <div style={{ position: 'absolute', right: '65px', bottom: '80px', }}>
          {/* 适应画布、100% */}
          <Select
            style={{
              width: '100px',
            }}
            value={screenFit}
            placeholder="缩放比列"
            onSelect={(v: any) => {
              this.handleGraphFit(v);
            }}
            options={[
              {
                value: '1',
                label: '适应画布',
              },
              {
                value: '2',
                label: '100%',
              },
            ]}
          />
        </div>
      </Modal>
    );
  }
}
export default connect(mapStateToProps)(BreakdownViewModal);
